package com.mspbots.core.teams.service.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.base.Splitter;
import com.mspbots.common.TimeZoneUtils;
import com.mspbots.core.AbstractBaseServiceImpl;
import com.mspbots.core.script.model.SystemScript;
import com.mspbots.core.script.service.SystemScriptService;
import com.mspbots.core.teams.mapper.MessagesMapper;
import com.mspbots.core.teams.mapper.TeamsUserMapper;
import com.mspbots.core.teams.model.BotMessageCacheDTO;
import com.mspbots.core.teams.model.Messages;
import com.mspbots.core.teams.model.MessagesIncontrollable;
import com.mspbots.core.teams.model.TeamsUser;
import com.mspbots.core.teams.service.MessagesService;
import com.mspbots.core.wise.mapper.TenantUserCountMapper;
import com.mspbots.core.wise.mapper.TenantUserTimeEntryMapper;
import com.mspbots.core.wise.mapper.UsersMapper;
import com.mspbots.core.wise.model.TenantUser;
import com.mspbots.core.wise.model.TenantUserCount;
import com.mspbots.core.wise.model.Users;
import com.mspbots.core.wise.model.dto.TimeEntryBotReport;
import com.mspbots.core.wise.service.TenantUserService;
import com.mspbots.cw.request.MessagesDTO;
import com.mspbots.cw.request.TriggerEscalationDTO;
import com.mspbots.dto.statistics.MessagesStatisticDTO;
import com.mspbots.dto.statistics.MessagesStatisticUserDTO;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;


/**
 * @author billb
 */
@Log4j2
@Service
@RequiredArgsConstructor
public class MessagesServiceImpl extends AbstractBaseServiceImpl<MessagesMapper, Messages> implements MessagesService {

    private final TenantUserService tenantUserService;
    private final SystemScriptService systemScriptService;
    private final RedisTemplate<String, Object> redisTemplate;
    private final TenantUserCountMapper tenantUserCountMapper;
    private final TenantUserTimeEntryMapper tenantUserTimeEntryMapper;
    private final UsersMapper usersMapper;
    private final TeamsUserMapper teamsUserMapper;

    @Override
    public int countMessagesByForRule(Messages query) {
        LocalDateTime createDate = query.getCreateDate();
        query.setCreateDate(null);
        QueryWrapper<Messages> queryWrapper = new QueryWrapper<>(query);
        if (createDate != null) {
            queryWrapper.between("create_date", LocalDateTime.of(createDate.toLocalDate(), LocalTime.MIN),
                    LocalDateTime.of(createDate.toLocalDate(), LocalTime.MAX));
        }
        if (query.getCreateDateFrom() != null) {
            queryWrapper.ge("create_date", query.getCreateDateFrom());
        }
        if (query.getCreateDateTo() != null) {
            queryWrapper.le("create_date", query.getCreateDateTo());
        }
        return this.baseMapper.selectCount(queryWrapper);
    }

    @Override
    public int countEscalation(Messages query) {
        Date createDate = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String imptimeBegin = null;
        Calendar cal = Calendar.getInstance();
        cal.setTime(createDate);
        if (cal.get(Calendar.DAY_OF_WEEK) == 1) {
            cal.add(Calendar.DATE, -6);
            imptimeBegin = sdf.format(cal.getTime());
        } else if (cal.get(Calendar.DAY_OF_WEEK) == 2) {
            imptimeBegin = sdf.format(cal.getTime());
        } else {
            cal.add(Calendar.DATE, 2 - cal.get(Calendar.DAY_OF_WEEK));
            imptimeBegin = sdf.format(cal.getTime());
        }
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        query.setCreateDate(LocalDate.parse(imptimeBegin, DateTimeFormatter.ISO_LOCAL_DATE).atStartOfDay());
        return this.baseMapper.countEscalation(query);
    }

    @Override
    public List<Messages> list(Wrapper<Messages> query) {
        List<Messages> messagesList = super.list(query);
        return messagesList.parallelStream().peek(message -> {
            TenantUser tenantUser = tenantUserService.getById(message.getUserId());
            if (!ObjectUtils.isEmpty(tenantUser)) {
                message.setTeamsUserName(tenantUser.getFirstname() + " " + tenantUser.getLastname());
            }
//            TenantTeamsUser user = this.teamsUserService.selectByTeamsUserId(message.getTenantId(),
//                    message.getTeamsUserId());
//            if (!ObjectUtils.isEmpty(user)) {
//                message.setTeamsUserName(user.getTeamsDisplayName());
//            }
            SystemScript rule = this.systemScriptService.getById(message.getRuleId());
//            SystemRule rule = this.ruleService.getById(message.getRuleId());
            if (!ObjectUtils.isEmpty(rule)) {
                message.setRuleName(rule.getName());
            }
        }).collect(Collectors.toList());
    }

    @Override
    public List<Messages> listSend(Messages query) {
        return this.baseMapper.findList(query);
    }

    @Override
    public List<MessagesDTO> findByTimeEntryId(Long entryId) {
        return this.baseMapper.findByTimeEntryId(entryId);
    }

    @Override
    public List<MessagesStatisticDTO> countByType(Long tenantId) {
        return baseMapper.countByType(tenantId);
    }

    @Override
    public List<MessagesStatisticDTO> countByDay(MessagesStatisticDTO messagesStatisticDTO) {
        messagesStatisticDTO = convertUser(messagesStatisticDTO);
        messagesStatisticDTO.setDateTo1(messagesStatisticDTO.getDateTo().toString());
        messagesStatisticDTO.setDateFrom1(messagesStatisticDTO.getDateFrom().toString());
        messagesStatisticDTO.setDateTo(messagesStatisticDTO.getDateTo().plusDays(1));
        List<MessagesStatisticDTO> messagesStatisticDTOS = this.baseMapper.countByDay(messagesStatisticDTO);
        long[] x = new long[messagesStatisticDTOS.size()];
        for (int i = 0; i < x.length; i++) {
            x[i] = i + 1;
        }
        int[] y = messagesStatisticDTOS.stream().mapToInt(dto -> dto.getTotalNum()).toArray();
        Map<String, Double> result = this.leastSquaresRegression(x, y);
        double slope = result.get("slope");
        double intercept = result.get("intercept");
        for (int i = 0; i < messagesStatisticDTOS.size(); i++) {
            double point = slope * (i + 1) + intercept;
            messagesStatisticDTOS.get(i).setPoint(point);
        }

        return messagesStatisticDTOS;
    }

    private MessagesStatisticDTO convertUser(MessagesStatisticDTO messagesStatisticDTO){
        if(!ObjectUtils.isEmpty(messagesStatisticDTO.getUserId())){
            Users user = this.usersMapper.selectById(messagesStatisticDTO.getUserId());
            List<TeamsUser> teamsUsers = this.teamsUserMapper.selectTeamsUser(user);
            List<TeamsUser> activeTeamsUser = teamsUsers.stream()
                    .filter(teamsUser -> !ObjectUtils.isEmpty(teamsUser.getSituation())
                            && teamsUser.getSituation().equals("active"))
                    .collect(Collectors.toList());

            if(!CollectionUtils.isEmpty(activeTeamsUser)){
                messagesStatisticDTO.setTeamsUserId(activeTeamsUser.get(0).getTeamsUserId());
            }else{
                if(!CollectionUtils.isEmpty(teamsUsers)){
                    messagesStatisticDTO.setTeamsUserId(teamsUsers.get(0).getTeamsUserId());
                }else{
                    messagesStatisticDTO.setTeamsUserId(null);
                }
            }
        }

        return messagesStatisticDTO;
    }


    private MessagesStatisticUserDTO convertUser(MessagesStatisticUserDTO messagesStatisticDTO){
        if(!ObjectUtils.isEmpty(messagesStatisticDTO.getUserId())){
            Users user = this.usersMapper.selectById(messagesStatisticDTO.getUserId());
            List<TeamsUser> teamsUsers = this.teamsUserMapper.selectTeamsUser(user);
            List<TeamsUser> activeTeamsUser = teamsUsers.stream()
                    .filter(teamsUser -> !ObjectUtils.isEmpty(teamsUser.getSituation())
                            && teamsUser.getSituation().equals("active"))
                    .collect(Collectors.toList());

            if(!CollectionUtils.isEmpty(activeTeamsUser)){
                messagesStatisticDTO.setTeamsUserId(activeTeamsUser.get(0).getTeamsUserId());
            }else{
                if(!CollectionUtils.isEmpty(teamsUsers)){
                    messagesStatisticDTO.setTeamsUserId(teamsUsers.get(0).getTeamsUserId());
                }else{
                    messagesStatisticDTO.setTeamsUserId(null);
                }
            }
        }
        return messagesStatisticDTO;
    }




    public Set<String> dealWithTeam(List<String> list){
        Set<String> set = new HashSet<>();
        list.stream().forEach(s -> {
            JsonNode jsonArr;
            try {
                if(!ObjectUtils.isEmpty(s)){
                    jsonArr = this.objectMapper.readTree(s);
                }else{
                    jsonArr = null;
                }
            }catch (JsonProcessingException e) {
                jsonArr = null;
                log.error("JsonProcessingException::"+e.getMessage());
                e.printStackTrace();
            }
            if(!ObjectUtils.isEmpty(jsonArr)){
                for (JsonNode json:jsonArr) {
                    if(json.has("name")){
                        set.add(json.get("name").asText());
                    }
                }
            }
        });
        return set;
    }

    @Override
    public IPage<MessagesDTO> reportPage(Page page, MessagesDTO query) {

        if(!ObjectUtils.isEmpty(query.getUserId())) {
            String teamsUserId = getTeamsUserIdByUser(query);
            if (!ObjectUtils.isEmpty(teamsUserId)) {
                query.setTeamsUserId(teamsUserId);
            }
        }

        List<MessagesDTO> list = this.baseMapper.reportPage(page, query);
        page.setRecords(list);
        return page;
    }



    private String getTeamsUserIdByUser(MessagesDTO query){
        Users user = this.usersMapper.selectById(query.getUserId());

        List<TeamsUser> teamsUsers = teamsUserMapper.selectTeamsUser(user);

        if(!CollectionUtils.isEmpty(teamsUsers)){
            if(teamsUsers.size() == 1){
                return teamsUsers.get(0).getTeamsUserId();
            }else{
                List<TeamsUser> activeUsers = teamsUsers.stream().filter(u -> !ObjectUtils.isEmpty(u.getSituation()) && u.getSituation().equalsIgnoreCase("active")).collect(Collectors.toList());
                if(!CollectionUtils.isEmpty(activeUsers)){
                    return activeUsers.get(0).getTeamsUserId();
                }else{
                    return teamsUsers.get(0).getTeamsUserId();
                }
            }

        }else{
            log.debug("getTeamsUserIdByUser not find teamsuser tenant: {} userid:{}",query.getTenantId(),query.getUserId());
            return null;
        }
    }

    @Override
    public int countByGroupUser(Long tenantId) {
        return baseMapper.countByGroupUser(tenantId);
    }


    @Override
    public TriggerEscalationDTO triggerEscalationList(TriggerEscalationDTO query) {
//        Date createDate = new Date();
//        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
//        String imptimeBegin = null;
        Calendar cal = Calendar.getInstance();
        if (StringUtils.isEmpty(query.getCreateDate())) {
            Date createDate = new Date();
            cal.setTime(createDate);
        } else {
            cal.setTime(query.getCreateDate());
        }
        if (cal.get(Calendar.DAY_OF_WEEK) == 1) {
            query.setDate((long) 1);
        }
        return baseMapper.triggerEscalationList(query);
    }

    @Override
    public Page<MessagesStatisticUserDTO> countByDayUser(Page<MessagesStatisticUserDTO> page, MessagesStatisticUserDTO messagesStatisticUserDTO) {
        messagesStatisticUserDTO = convertUser(messagesStatisticUserDTO);
        messagesStatisticUserDTO.setDateTo(messagesStatisticUserDTO.getDateTo().plusDays(1));
        Page<MessagesStatisticUserDTO> messagesStatisticUserDTOPage = baseMapper.countByDayUser(page, messagesStatisticUserDTO);
        List<MessagesStatisticUserDTO> MessagesStatisticUserDTOs = messagesStatisticUserDTOPage.getRecords();
        for (MessagesStatisticUserDTO messagesStatisticUser : MessagesStatisticUserDTOs) {
            List<String> CreateDateList = Splitter.on(",").trimResults().splitToList(messagesStatisticUser.getCreateDates());
            messagesStatisticUser.setCreateDateList(CreateDateList);
            List<String> dayTotalList = new ArrayList<>(Splitter.on(",").trimResults().splitToList(messagesStatisticUser.getDayTotal()));
            messagesStatisticUser.setDayTotalList(dayTotalList);
        }
        this.processCountByDayUserData(MessagesStatisticUserDTOs,messagesStatisticUserDTO);
        return messagesStatisticUserDTOPage.setRecords(MessagesStatisticUserDTOs);
    }

    private void processCountByDayUserData(List<MessagesStatisticUserDTO> tos,MessagesStatisticUserDTO to){
        if (CollectionUtils.isEmpty(tos)){
            return;
        }

        long days = to.getDateFrom().until(to.getDateTo(), ChronoUnit.DAYS);
        List<String> newCreateDateList = new ArrayList<>();
        for (int i = 0; i < days; i++){
            newCreateDateList.add(to.getDateFrom().plusDays(i).toString());
        }
        tos.stream().filter(t -> t.getCreateDateList().size() < days).forEach(t ->{
            for (int i = 0; i < newCreateDateList.size(); i++){
                if (!t.getCreateDateList().contains(newCreateDateList.get(i))){
                    t.getDayTotalList().add(i,"0");
                }
            }
            t.setCreateDateList(newCreateDateList);
        });
    }

    @Override
    public synchronized Object insertMessages(Messages entity) {
        return baseMapper.insertMessages(entity);
    }

    @Override
    public List<MessagesIncontrollable> incontrollable(MessagesIncontrollable params) {
        return baseMapper.incontrollable(params);
    }

    private static final String REDIS_KEY_PREFIX_USER = "mspbots:users:bot:";

    @Override
    public Object cacheMsgCount(BotMessageCacheDTO query) {
        String cacheKey = REDIS_KEY_PREFIX_USER + query.getUserId() + ":" + query.getScriptId();
        Object lastTimeCache = redisTemplate.opsForHash().get(cacheKey,"time") ;
        LocalDateTime lastTime = LocalDateTime.now();
        if (lastTimeCache != null) {
            lastTime = LocalDateTime.parse(lastTimeCache.toString(), DateTimeFormatter.ISO_ZONED_DATE_TIME);
        }
        query.setTime(lastTime);
        // max messages create time
        LocalDateTime maxMsgTime = baseMapper.maxCreateTime(query);

        Object numCache = redisTemplate.opsForHash().get(cacheKey,"num");
        log.debug("cache info : {} {} {} {} {}", query.getUserId(), query.getScriptId(), lastTime, maxMsgTime, numCache);
        Integer num = 0;
        if (numCache == null) {
            if (maxMsgTime == null) {
                maxMsgTime = LocalDateTime.now();
            }
            redisTemplate.opsForHash().put(cacheKey,"time", maxMsgTime);
            redisTemplate.opsForHash().put(cacheKey,"num", num +1);
            redisTemplate.opsForHash().put(cacheKey,"highest", num +1);

            TenantUserCount tenantUserCount = new TenantUserCount();
            tenantUserCount.setUserId(query.getUserId());
            tenantUserCount.setNum(1);
            tenantUserCount.setType("user_script_highest");
            tenantUserCount.setTenantId(query.getTenantId());
            tenantUserCount.setCreateTime(LocalDateTime.now());
            tenantUserCount.setBusinessId(query.getScriptId());
            tenantUserCount.setBusinessTime(maxMsgTime);
            tenantUserCountMapper.insert(tenantUserCount);
        } else {
            num = Integer.parseInt(numCache.toString());
            // no bot trigger
            if (maxMsgTime != null)  {
                redisTemplate.opsForHash().put(cacheKey,"num", 0);
                redisTemplate.opsForHash().put(cacheKey,"time", maxMsgTime);
            } else {
                redisTemplate.opsForHash().put(cacheKey,"num", num+1);
            }

            TenantUserCount tenantUserCount = tenantUserCountMapper.selectOne(Wrappers.<TenantUserCount>lambdaQuery()
                    .eq(TenantUserCount::getTenantId, query.getTenantId())
                    .eq(TenantUserCount::getUserId, query.getUserId())
                    .eq(TenantUserCount::getBusinessId, query.getScriptId())
                    .eq(TenantUserCount::getType, "user_script_highest")
            );


            if (num > tenantUserCount.getNum()) {
                tenantUserCount.setNum(num);
                tenantUserCount.setUpdateTime(LocalDateTime.now());
                tenantUserCountMapper.updateById(tenantUserCount);
                redisTemplate.opsForHash().put(cacheKey,"highest", num);
            }
        }



        // get last time
        log.debug("after cache info : {} {} {} ", query.getUserId(), query.getScriptId(), redisTemplate.opsForHash().get(cacheKey,"num"));

        return true;
    }


    @Override
    public Object getCacheMsgCount(BotMessageCacheDTO query) {
        String cacheKey = REDIS_KEY_PREFIX_USER + query.getUserId() + ":" + query.getScriptId();
        Object num = redisTemplate.opsForHash().get(cacheKey,"num");
        Object time = redisTemplate.opsForHash().get(cacheKey,"time");
        Object ownHighest = redisTemplate.opsForHash(). get(cacheKey,"highest");



        LocalDateTime currentTime = TimeZoneUtils.utcToZone(LocalDateTime.now(),"UTC").toLocalDateTime();
        int month = getQuarterMonth(currentTime.getMonth().getValue());
        currentTime = currentTime.withMonth(month).withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0).withNano(0);
        log.debug("getCacheMsgCount:currentTime:{}",currentTime);
        query.setTime(currentTime);

        int companyHighest;
        String highestName;

        TenantUserCount count = tenantUserCountMapper.selectQuarterHighest(query);
        log.debug("getCacheMsgCount:count:{}",count);
        if(ObjectUtils.isEmpty(count)){
            companyHighest = 0;
            highestName = "mspbots";
        }else{
            companyHighest = count.getNum();
            Users user = usersMapper.selectById(count.getUserId());
            if(ObjectUtils.isEmpty(user)){
                highestName = "mspbots";
            }else{
                String firstName = ObjectUtils.isEmpty(user.getFirstName())?"":user.getFirstName();
                String lastName = ObjectUtils.isEmpty(user.getLastName())?"":user.getLastName();
                highestName = firstName+lastName;
            }
        }

        if (num == null) {
            return Map.of("time", LocalDateTime.now(), "num", 0, "highest", 0);
        } else if (Integer.parseInt(num.toString())==0) {
            return Map.of("time", time, "num", 0 , "ownHighest", ownHighest,"companyHighest",companyHighest,"highestName",highestName);

        }

        return Map.of("time", time, "num", Integer.parseInt(num.toString()) -1 , "ownHighest", ownHighest,"companyHighest",companyHighest,"highestName",highestName);
    }

    @Override
    public Object countTimeEntryBot(BotMessageCacheDTO query) {
        TimeEntryBotReport timeEntryBotReport = new TimeEntryBotReport();
        BeanUtils.copyProperties(query, timeEntryBotReport);
        log.debug("==================timeEntryBotReport : {}", timeEntryBotReport);
        LocalDateTime lastEnteredDate = tenantUserTimeEntryMapper.lastEnteredDate(timeEntryBotReport);
        LocalDateTime currentTime = TimeZoneUtils.utcToZone(LocalDateTime.now(),"UTC").toLocalDateTime();
//        int month = getQuarterMonth(currentTime.getMonth().getValue());
        currentTime = currentTime.withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0).withNano(0);
        if (ObjectUtils.isEmpty(lastEnteredDate)) {
            lastEnteredDate = currentTime;
        }

        timeEntryBotReport.setEnteredDateStart(lastEnteredDate);
        timeEntryBotReport.setEnteredDateEnd(query.getTime());
        log.debug("==================timeEntryBotReport : {}", timeEntryBotReport);
        Integer num = tenantUserTimeEntryMapper.countTimeEntryBot(timeEntryBotReport);
        log.debug("==================timeEntryBotReport num : {}", num);
        TenantUserCount tenantUserCount = tenantUserCountMapper.selectOne(Wrappers.<TenantUserCount>lambdaQuery()
                .eq(TenantUserCount::getTenantId, query.getTenantId())
                .eq(TenantUserCount::getUserId, query.getUserId())
                .eq(TenantUserCount::getBusinessId, query.getScriptId())
                .eq(TenantUserCount::getType, "user_script_highest")
        );


        if (tenantUserCount == null) {
            tenantUserCount = new TenantUserCount();
            tenantUserCount.setUserId(query.getUserId());
            tenantUserCount.setNum(num);
            tenantUserCount.setType("user_script_highest");
            tenantUserCount.setTenantId(query.getTenantId());
            tenantUserCount.setCreateTime(LocalDateTime.now());
            tenantUserCount.setUpdateTime(LocalDateTime.now());
            tenantUserCount.setBusinessId(query.getScriptId());
            tenantUserCount.setBusinessTime(query.getTime());
            tenantUserCountMapper.insert(tenantUserCount);
        } else {
            log.debug("==================timeEntryBotReport tenantUserCount : {}", tenantUserCount.getNum() );
            if (num > tenantUserCount.getNum()) {
                tenantUserCount.setNum(num);
                tenantUserCount.setUpdateTime(LocalDateTime.now());
                tenantUserCount.setBusinessTime(query.getTime());
                tenantUserCountMapper.updateById(tenantUserCount);
            }
        }


        Integer companyHighest = 0;
        String highestName = "mspbots";



        log.debug("==================timeEntryBotReport currentTime:{}",currentTime);
        query.setTime(currentTime);
        TenantUserCount count = tenantUserCountMapper.selectQuarterHighest(query);

        if(!ObjectUtils.isEmpty(count)){
            companyHighest = count.getNum();
            Users user = usersMapper.selectById(count.getUserId());
            if(ObjectUtils.isEmpty(user)){
                highestName = "mspbots";
            }else{
                String firstName = ObjectUtils.isEmpty(user.getFirstName())?"":user.getFirstName();
                String lastName = ObjectUtils.isEmpty(user.getLastName())?"":user.getLastName();
                highestName = firstName+lastName;
            }
        }

        return Map.of(
                "time", query.getTime(),
                "num", num ,
                "ownHighest", tenantUserCount.getNum(),
                "companyHighest",companyHighest,
                "highestName",highestName);

    }

    private int getQuarterMonth(int value) {
        if( value <= 3){
            return 1;
        }else if(value > 3 && value <= 6){
            return 4;
        }
        else if(value > 6 && value <= 9){
            return 7;
        }else{
            return 10;
        }
    }

    @Override
    public boolean removeCache(Long userId) {
        String cacheKey = REDIS_KEY_PREFIX_USER + userId + ":*";
        Set<String> keys = redisTemplate.keys(cacheKey);
        return redisTemplate.delete(keys) > 0;
    }

    public Map<String, Double> leastSquaresRegression(long[] x, int[] y) {
        int n = x.length;
        double sumx = 0.0, sumy = 0.0, sumx2 = 0.0, sumxy = 0.0;
        for (int i = 0; i < n; i++) {
            sumx += x[i];
            sumy += y[i];
            sumx2 += x[i] * x[i];
            sumxy += x[i] * y[i];
        }
        double divisor = n * sumxy - sumx * sumy;
        double dividend = n * sumx2 - sumx * sumx;
        double slope = divisor / dividend;
        double intercept = (sumy - slope * sumx) / n;
        Map<String, Double> result = Map.of("slope", slope, "intercept", intercept);
        return result;
    }
}
